/**************************************************************************
 *                                                                        *
 *         Copyright (c) 2014 by Generalplus Inc.                         *
 *                                                                        *
 *  This software is copyrighted by and is the property of Generalplus    *
 *  Inc. All rights are reserved by Generalplus Inc.                      *
 *  This software may only be used in accordance with the                 *
 *  corresponding license agreement. Any unauthorized use, duplication,   *
 *  distribution, or disclosure of this software is expressly forbidden.  *
 *                                                                        *
 *  This Copyright notice MUST not be removed or modified without prior   *
 *  written consent of Generalplus Technology Co., Ltd.                   *
 *                                                                        *
 *  Generalplus Inc. reserves the right to modify this software           *
 *  without notice.                                                       *
 *                                                                        *
 *  Generalplus Inc.                                                      *
 *  No.19, Industry E. Rd. IV, Hsinchu Science Park                       *
 *  Hsinchu City 30078, Taiwan, R.O.C.                                    *
 *                                                                        *
 **************************************************************************/
/********************************************************************
* Purpose:  COMS censor interface layer 1 driver
* Author:
* Date: 	2014/09/09
* Copyright Generalplus Corp. ALL RIGHTS RESERVED.
* Version : 1.00
* History :
*********************************************************************/
#include "drv_l1_sfr.h"
#include "drv_l1_i2c.h"
#include "drv_l1_csi.h"

//=== This is for code configuration DON'T REMOVE or MODIFY it ===//
#if (defined _DRV_L1_CSI) && (_DRV_L1_CSI == 1) //

//================================================================//

/****************************************************
*		Definition 									*
****************************************************/
typedef struct
{	// Offset
	volatile INT32U CSI_SEN_IRQSTS;		// 0x0000
	volatile INT32U CSI_SEN_IRQEN;		// 0x0004
	volatile INT32U CSI_TG_CTRL1;		// 0x0008
	volatile INT32U CSI_TG_CTRL2;		// 0x000C
	volatile INT32U CSI_TG_HLSTART;		// 0x0010
	volatile INT32U CSI_TG_HEND;		// 0x0014
	volatile INT32U CSI_TG_VL0START;	// 0x0018
	volatile INT32U CSI_MD_FBADDR;		// 0x001C
	volatile INT32U CSI_TG_VEND;		// 0x0020
	volatile INT32U CSI_TG_HSTART;		// 0x0024
	volatile INT32U CSI_MD_RGBL;		// 0x0028
	volatile INT32U CSI_SEN_CTRL;		// 0x002C
	volatile INT32U CSI_TG_BSUPPER;		// 0x0030
	volatile INT32U CSI_TG_BSLOWER;		// 0x0034
	volatile INT32U CSI_MD_RGBH;		// 0x0038
	volatile INT32U CSI_MD_CTRL;		// 0x003C
	volatile INT32U CSI_TG_FBSADDR;		// 0x0040
	volatile INT32U RESERVED_1;			// 0x0044
	volatile INT32U CSI_TG_VL1START;	// 0x0048
	volatile INT32U CSI_TG_HWIDTH;		// 0x004C
	volatile INT32U CSI_TG_VWIDTH;		// 0x0050
	volatile INT32U CSI_TG_CUTSTART;	// 0x0054
	volatile INT32U CSI_TG_CUTSIZE;		// 0x0058
	volatile INT32U CSI_TG_VSTART;		// 0x005C
	volatile INT32U CSI_MD_FBADDRH;		// 0x0060
	volatile INT32U CSI_HRATIO;			// 0x0064
	volatile INT32U CSI_VRATIO;			// 0x0068
	volatile INT32U CSI_MD_HPOS;		// 0x006C
	volatile INT32U CSI_MD_VPOS;		// 0x0070
	volatile INT32U CSI_TG_FBSADDR_B;	// 0x0074
	volatile INT32U CSI_JPEG_BYTE;		// 0x0078
} CSI0_CONTROL_SFR;

typedef struct
{	// Offset
	volatile INT32U CSI_TG_FBSADDR_B;	// 0x0000
	volatile INT32U CSI_SEN_IRQSTS;		// 0x0004
	volatile INT32U CSI_SEN_IRQEN;		// 0x0008
	volatile INT32U CSI_TG_CTRL1;		// 0x000C
	volatile INT32U CSI_TG_CTRL2;		// 0x0010
	volatile INT32U CSI_TG_HLSTART;		// 0x0014
	volatile INT32U CSI_TG_HEND;		// 0x0018
	volatile INT32U CSI_TG_VL0START;	// 0x001C
	volatile INT32U CSI_TG_VEND;		// 0x0020
	volatile INT32U CSI_TG_HSTART;		// 0x0024
	volatile INT32U CSI_TG_FBSADDR;		// 0x0028
	volatile INT32U CSI_TG_VL1START;	// 0x002C
	volatile INT32U CSI_TG_HWIDTH;		// 0x0030
	volatile INT32U CSI_TG_VWIDTH;		// 0x0034
	volatile INT32U CSI_TG_CUTSTART;	// 0x0038
	volatile INT32U CSI_TG_CUTSIZE;		// 0x003C
	volatile INT32U CSI_TG_VSTART;		// 0x0040
	volatile INT32U CSI_HRATIO;			// 0x0044
	volatile INT32U CSI_VRATIO;			// 0x0048
} CSI1_CONTROL_SFR;


#define MD_EN				(1<<1)			// Enable H/W motion detection (MD)
#define MD_FRAME_1			(0<<2)			// MD detects every frame
#define MD_FRAME_2			(1<<2)			// MD detects every 2 frame
#define MD_FRAME_4			(2<<2)			// MD detects every 4 frame
#define MD_FRAME_8			(3<<2)			// MD detects every 8 frame
#define MD_VGA				(1<<4)			// VGA / QVGA size
#define MD_YUV				(1<<5)			// YUV / RGB data type
#define MD_MODE_AVE			(0<<6)			// Average mode
#define MD_MODE_SINGLE		(1<<6)			// Single mode
#define MD_MODE_AVEIIR		(2<<6)			// Average IIR mode
#define MD_MODE_SINGLEIIR	(3<<6)			// Single IIR mode
#define THRESHOLD			10
#define MD_THRESHOLD        (THRESHOLD<<9)	//max 1800


/****************************************************
*		varaible and data declaration				*
****************************************************/
static CSI_CALLBACK_FUN csi_callback[CSI_DEV_NUM] = { NULL };

/*****************************************
*			CSI functions				 *
*****************************************/
static void *get_CSI_Reg_Base(INT8U csiDevNum)
{
	if(csiDevNum == CSI_DEV_0)
	{
		return (void *) P_CSI0_CONTROL_BASE;
	}
	else
	{
		return (void *) P_CSI1_CONTROL_BASE;
	}
}

void drv_l1_csi_init(INT8U csiDevNum)
{
	CSI0_CONTROL_SFR	*pCsi0_Reg;
	CSI1_CONTROL_SFR	*pCsi1_Reg;

	if(csiDevNum == 0)
	{
		pCsi0_Reg = (CSI0_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		/* set horizontal/vertical scale ratio to 0 */
		pCsi0_Reg->CSI_HRATIO = 0;
		pCsi0_Reg->CSI_VRATIO = 0;

		/* Sensor field 0 vertical latch start register */
		pCsi0_Reg->CSI_TG_VL0START = 0x0000;

		/* *P_Sensor_TG_V_L1Start = 0x0000 */
		pCsi0_Reg->CSI_TG_VL1START = 0x0000;

		/* Sensor horizontal start register */
		pCsi0_Reg->CSI_TG_HSTART = 0x0000;

		/* reset control 0/1 */
		pCsi0_Reg->CSI_TG_CTRL1 = 0;
		pCsi0_Reg->CSI_TG_CTRL2 = 0;
	}
	else
	{
		pCsi1_Reg = (CSI1_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		/* set horizontal/vertical scale ratio to 0 */
		pCsi1_Reg->CSI_HRATIO = 0;
		pCsi1_Reg->CSI_VRATIO = 0;

		/* Sensor field 0 vertical latch start register */
		pCsi1_Reg->CSI_TG_VL0START = 0x0000;

		/* *P_Sensor_TG_V_L1Start = 0x0000 */
		pCsi1_Reg->CSI_TG_VL1START = 0x0000;

		/* Sensor horizontal start register */
		pCsi1_Reg->CSI_TG_HSTART = 0x0000;

		/* reset control 0/1 */
		pCsi1_Reg->CSI_TG_CTRL1 = 0;
		pCsi1_Reg->CSI_TG_CTRL2 = 0;
	}
}

void drv_l1_csi_uninit(INT8U csiDevNum)
{
	CSI0_CONTROL_SFR	*pCsi0_Reg;
	CSI1_CONTROL_SFR	*pCsi1_Reg;

	if(csiDevNum == 0)
	{
		pCsi0_Reg = (CSI0_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		// csi disable
		pCsi0_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_CSIEN;	//disable sensor controller
		pCsi0_Reg->CSI_TG_CTRL2 &= ~MASK_CSI_CTRL1_CLKOEN;	//disable sensor clock out
	}
	else
	{
		pCsi1_Reg = (CSI1_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		// csi disable
		pCsi1_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_CSIEN;	//disable sensor controller
		pCsi1_Reg->CSI_TG_CTRL2 &= ~MASK_CSI_CTRL1_CLKOEN;	//disable sensor clock out
	}
}

void drv_l1_csi_start(INT8U csiDevNum)
{
	CSI0_CONTROL_SFR	*pCsi0_Reg;
	CSI1_CONTROL_SFR	*pCsi1_Reg;

	if(csiDevNum == 0)
	{
		pCsi0_Reg = (CSI0_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		/* Clear sensor interrupt status */
		pCsi0_Reg->CSI_SEN_IRQSTS = 0x3F;

		/* enable frame end interrupt */
		pCsi0_Reg->CSI_SEN_IRQEN |= MASK_CSI_FRAME_END_FLAG | MASK_CSI_FIFO_OVERFLOW_FLAG;

		/* enable CSI module */
		pCsi0_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_CSIEN | MASK_CSI_CTRL0_OWN_IRQ | MASK_CSI_CTRL0_CAP;
	}
	else
	{
		pCsi1_Reg = (CSI1_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		/* Clear sensor interrupt status */
		pCsi1_Reg->CSI_SEN_IRQSTS = 0x3F;

		/* enable frame end interrupt */
		pCsi1_Reg->CSI_SEN_IRQEN |= MASK_CSI_FRAME_END_FLAG | MASK_CSI_FIFO_OVERFLOW_FLAG;

		/* enable CSI module */
		pCsi1_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_CSIEN | MASK_CSI_CTRL0_OWN_IRQ | MASK_CSI_CTRL0_CAP;
	}
}

void drv_l1_csi_stop(INT8U csiDevNum)
{
	CSI0_CONTROL_SFR	*pCsi0_Reg;
	CSI1_CONTROL_SFR	*pCsi1_Reg;

	if(csiDevNum == 0)
	{
		pCsi0_Reg = (CSI0_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		/* Disable sensor interrupt */
		pCsi0_Reg->CSI_SEN_IRQEN &= ~MASK_CSI_FRAME_END_ENABLE;

		/* Disable CSI module */
		pCsi0_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_CSIEN;

		/* Disable sensor output clock*/
		pCsi0_Reg->CSI_TG_CTRL2 &= ~MASK_CSI_CTRL1_CLKOEN;

		/* Clear sensor interrupt status */
		pCsi0_Reg->CSI_SEN_IRQSTS = 0x3F;
	}
	else
	{
		pCsi1_Reg = (CSI1_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		/* Disable sensor interrupt */
		pCsi1_Reg->CSI_SEN_IRQEN &= ~MASK_CSI_FRAME_END_ENABLE;

		/* Disable CSI module */
		pCsi1_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_CSIEN;

		/* Disable sensor output clock*/
		pCsi1_Reg->CSI_TG_CTRL2 &= ~MASK_CSI_CTRL1_CLKOEN;

		/* Clear sensor interrupt status */
		pCsi1_Reg->CSI_SEN_IRQSTS = 0x3F;
	}
}

void drv_l1_csi_input_set(INT8U csiDevNum, CSI_INPUT_INTERFACE_DEF interface, CSI_INTERLACE_MODE_DEF interlace, INT32U invert_clk, CSI_INPUT_DATA_DEF data_format)
{
	CSI0_CONTROL_SFR	*pCsi0_Reg;
	CSI1_CONTROL_SFR	*pCsi1_Reg;

	if(csiDevNum == 0)
	{
		pCsi0_Reg = (CSI0_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		if(interface == CSI_HREF)
		{
			pCsi0_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_HREF;
			pCsi0_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_CCIR656;
		}
		else
		if(interface == CSI_HSYNC_CCIR_656)
		{
			pCsi0_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_HREF;
			pCsi0_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_CCIR656;
			R_GPIOCTRL|= 1<<5;  // HSYNC / VSYNC use as GPIO
		}
		else
		{	// ENUM_CSI_HSYNC_CCIR_601
			pCsi0_Reg->CSI_TG_CTRL1 &= ~(MASK_CSI_CTRL0_CCIR656 | MASK_CSI_CTRL0_HREF);
		}

		if(interlace == CSI_NON_INTERLACE)
		{
			pCsi0_Reg->CSI_TG_CTRL1 &= ~(MASK_CSI_CTRL0_INTL | MASK_CSI_CTRL0_FIELDINV);
		}
		else
		if(interlace == CSI_INTERLACE)
		{
			pCsi0_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_FIELDINV;
			pCsi0_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_INTL;
		}
		else
		{	// ENUM_CSI_INTERLACE_INVERT_FIELD
			pCsi0_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_INTL | MASK_CSI_CTRL0_FIELDINV;
		}

		if(invert_clk)
		{
			pCsi0_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_CLKIINV;
		}
		else
		{
			pCsi0_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_CLKIINV;
		}

		if(data_format < CSI_IN_UYVY)
		{
			// RGB
			pCsi0_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_YUVIN;

			if(data_format == CSI_IN_RGB888_BGRG || data_format == CSI_IN_RGB888_GBGR)
			{
				pCsi0_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_CCIR656;
			}
			else
			{
				pCsi0_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_CCIR656;
				R_GPIOCTRL|= 1<<5;  // HSYNC / VSYNC use as GPIO
			}

			if(data_format == CSI_IN_RGB888_BGRG || data_format == CSI_IN_RGB888_GBGR)
			{
				pCsi0_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_YUVTYPE;
			}
			else
			{
				pCsi0_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_YUVTYPE;
			}
		}
		else
		{	// YUV
			pCsi0_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_YUVIN;

			if(data_format == CSI_IN_UYVY || data_format == CSI_IN_UYVY_INVERT_UV7)
			{
				pCsi0_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_YUVTYPE;
			}
			else
			{
				pCsi0_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_YUVTYPE;
			}

			if(data_format == CSI_IN_UYVY || data_format == CSI_IN_YUYV)
			{
				pCsi0_Reg->CSI_TG_CTRL2 &= ~MASK_CSI_CTRL1_INVYUVI;
			}
			else
			{
				pCsi0_Reg->CSI_TG_CTRL2 |= MASK_CSI_CTRL1_INVYUVI;
			}
		}
	}
	else
	{
		pCsi1_Reg = (CSI1_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		if(interface == CSI_HREF)
		{
			pCsi1_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_HREF;
			pCsi1_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_CCIR656;
		}
		else
		if(interface == CSI_HSYNC_CCIR_656)
		{
			pCsi1_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_HREF;
			pCsi1_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_CCIR656;
			R_GPIOCTRL|= 1<<5;  // HSYNC / VSYNC use as GPIO
		}
		else
		{	// ENUM_CSI_HSYNC_CCIR_601
			pCsi1_Reg->CSI_TG_CTRL1 &= ~(MASK_CSI_CTRL0_CCIR656 | MASK_CSI_CTRL0_HREF);
		}

		if(interlace == CSI_NON_INTERLACE)
		{
			pCsi1_Reg->CSI_TG_CTRL1 &= ~(MASK_CSI_CTRL0_INTL | MASK_CSI_CTRL0_FIELDINV);
		}
		else
		if(interlace == CSI_INTERLACE)
		{
			pCsi1_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_FIELDINV;
			pCsi1_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_INTL;
		}
		else
		{	// ENUM_CSI_INTERLACE_INVERT_FIELD
			pCsi1_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_INTL | MASK_CSI_CTRL0_FIELDINV;
		}

		if(invert_clk)
		{
			pCsi1_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_CLKIINV;
		}
		else
		{
			pCsi1_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_CLKIINV;
		}

		if(data_format < CSI_IN_UYVY)
		{
			// RGB
			pCsi1_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_YUVIN;

			if(data_format == CSI_IN_RGB888_BGRG || data_format == CSI_IN_RGB888_GBGR)
			{
				pCsi1_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_CCIR656;
			}
			else
			{
				pCsi1_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_CCIR656;
				R_GPIOCTRL|= 1<<5;  // HSYNC / VSYNC use as GPIO
			}

			if(data_format == CSI_IN_RGB888_BGRG || data_format == CSI_IN_RGB888_GBGR)
			{
				pCsi1_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_YUVTYPE;
			}
			else
			{
				pCsi1_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_YUVTYPE;
			}
		}
		else
		{	// YUV
			pCsi1_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_YUVIN;

			if(data_format == CSI_IN_UYVY || data_format == CSI_IN_UYVY_INVERT_UV7)
			{
				pCsi1_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_YUVTYPE;
			}
			else
			{
				pCsi1_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_YUVTYPE;
			}

			if(data_format == CSI_IN_UYVY || data_format == CSI_IN_YUYV)
			{
				pCsi1_Reg->CSI_TG_CTRL2 &= ~MASK_CSI_CTRL1_INVYUVI;
			}
			else
			{
				pCsi1_Reg->CSI_TG_CTRL2 |= MASK_CSI_CTRL1_INVYUVI;
			}
		}
	}
}

void drv_l1_csi_output_format_set(INT8U csiDevNum, CSI_OUTPUT_DATA_DEF data_format)
{
	CSI0_CONTROL_SFR	*pCsi0_Reg;
	CSI1_CONTROL_SFR	*pCsi1_Reg;

	if(csiDevNum == 0)
	{
		pCsi0_Reg = (CSI0_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		if(data_format < CSI_OUT_VYUY)
		{
			// RGB
			pCsi0_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_YUVOUT;

			if(data_format == CSI_OUT_RGB565)
			{
				pCsi0_Reg->CSI_TG_CTRL2 &= ~MASK_CSI_CTRL1_RGB1555;
			}
			else
			{
				pCsi0_Reg->CSI_TG_CTRL2 |= MASK_CSI_CTRL1_RGB1555;
			}
		}
		else
		if(data_format == CSI_OUT_Y_ONLY)
		{
			pCsi0_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_YUVOUT;
			pCsi0_Reg->CSI_TG_CTRL2 |= MASK_CSI_CTRL1_YONLY;
		}
		else
		{
			// YUV
			pCsi0_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_YUVOUT;

			if(data_format == CSI_OUT_VYUY || data_format == CSI_OUT_VYUY_INVERT_UV7)
			{
				pCsi0_Reg->CSI_TG_CTRL2 &= ~MASK_CSI_CTRL1_RGB1555;
			}
			else
			{
				pCsi0_Reg->CSI_TG_CTRL2 |= MASK_CSI_CTRL1_RGB1555;
			}

			if(data_format == CSI_OUT_VYUY || data_format == CSI_OUT_YUYV)
			{
				pCsi0_Reg->CSI_TG_CTRL2 &= ~MASK_CSI_CTRL1_INVYUVO;
			}
			else
			{
				pCsi0_Reg->CSI_TG_CTRL2 |= MASK_CSI_CTRL1_INVYUVO;
			}
		}
	}
	else
	{
		pCsi1_Reg = (CSI1_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		if(data_format < CSI_OUT_VYUY)
		{
			// RGB
			pCsi1_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_YUVOUT;

			if(data_format == CSI_OUT_RGB565)
			{
				pCsi1_Reg->CSI_TG_CTRL2 &= ~MASK_CSI_CTRL1_RGB1555;
			}
			else
			{
				pCsi1_Reg->CSI_TG_CTRL2 |= MASK_CSI_CTRL1_RGB1555;
			}
		}
		else
		if(data_format == CSI_OUT_Y_ONLY)
		{
			pCsi1_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_YUVOUT;
			pCsi1_Reg->CSI_TG_CTRL2 |= MASK_CSI_CTRL1_YONLY;
		}
		else
		{
			// YUV
			pCsi1_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_YUVOUT;

			if(data_format == CSI_OUT_VYUY || data_format == CSI_OUT_VYUY_INVERT_UV7)
			{
				pCsi1_Reg->CSI_TG_CTRL2 &= ~MASK_CSI_CTRL1_RGB1555;
			}
			else
			{
				pCsi1_Reg->CSI_TG_CTRL2 |= MASK_CSI_CTRL1_RGB1555;
			}

			if(data_format == CSI_OUT_VYUY || data_format == CSI_OUT_YUYV)
			{
				pCsi1_Reg->CSI_TG_CTRL2 &= ~MASK_CSI_CTRL1_INVYUVO;
			}
			else
			{
				pCsi1_Reg->CSI_TG_CTRL2 |= MASK_CSI_CTRL1_INVYUVO;
			}
		}
	}
}

void drv_l1_csi_output_fifo_set(INT8U csiDevNum, CSI_OUTPUT_FIFO_ENUM fifo_mode)
{
	CSI0_CONTROL_SFR	*pCsi0_Reg;
	CSI1_CONTROL_SFR	*pCsi1_Reg;

	if(csiDevNum == 0)
	{
		pCsi0_Reg = (CSI0_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		if(fifo_mode == ENUM_CSI_FIFO_DISABLE)
		{
			pCsi0_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_FIFO_MASK;
			pCsi0_Reg->CSI_SEN_IRQEN &= ~MASK_CSI_OUTPUT_FIFO_ENABLE;
		}
		else
		{
			pCsi0_Reg->CSI_TG_CTRL1 |= fifo_mode;
			pCsi0_Reg->CSI_SEN_IRQEN |= MASK_CSI_OUTPUT_FIFO_ENABLE;
		}
	}
	else
	{
		pCsi1_Reg = (CSI1_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		if(fifo_mode == ENUM_CSI_FIFO_DISABLE)
		{
			pCsi1_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_FIFO_MASK;
			pCsi1_Reg->CSI_SEN_IRQEN &= ~MASK_CSI_OUTPUT_FIFO_ENABLE;
		}
		else
		{
			pCsi1_Reg->CSI_TG_CTRL1 |= fifo_mode;
			pCsi1_Reg->CSI_SEN_IRQEN |= MASK_CSI_OUTPUT_FIFO_ENABLE;
		}
	}
}

INT32S drv_l1_csi_input_resolution_set(INT8U csiDevNum, INT32U width, INT32U height)
{
	CSI0_CONTROL_SFR	*pCsi0_Reg;
	CSI1_CONTROL_SFR	*pCsi1_Reg;

	if(width > 4095 || height > 4095)
	{
		return -1;
	}

	if(csiDevNum == 0)
	{
		pCsi0_Reg = (CSI0_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		pCsi0_Reg->CSI_TG_HWIDTH = width;
		pCsi0_Reg->CSI_TG_VWIDTH = height;
	}
	else
	{
		pCsi1_Reg = (CSI1_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		pCsi1_Reg->CSI_TG_HWIDTH = width;
		pCsi1_Reg->CSI_TG_VWIDTH = height;
	}

	return 0;
}

void drv_l1_csi_set_scale(INT8U csiDevNum, INT16U sw, INT16U tw, INT16U sh, INT16U th)
{
	CSI0_CONTROL_SFR	*pCsi0_Reg;
	CSI1_CONTROL_SFR	*pCsi1_Reg;

	if(csiDevNum == 0)
	{
		pCsi0_Reg = (CSI0_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		if(sw > tw)
		{
			pCsi0_Reg->CSI_HRATIO = ((sw >> 4) | (((tw >> 4) & 0xff) << 8));
		}

		if(sh > th)
		{
			pCsi0_Reg->CSI_VRATIO = ((sh >> 4) | (((th >> 4) & 0xff) << 8));
		}
	}
	else
	{
		pCsi1_Reg = (CSI1_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		if(sw > tw)
		{
			pCsi1_Reg->CSI_HRATIO = ((sw >> 4) | (((tw >> 4) & 0xff) << 8));
		}

		if(sh > th)
		{
			pCsi1_Reg->CSI_VRATIO = ((sh >> 4) | (((th >> 4) & 0xff) << 8));
		}
	}
}

// Latch control registers are used in HSYNC mode only. It is not used in HREF mode
void drv_l1_csi_input_latch_timing1_set(INT8U csiDevNum, INT32U h_start, INT32U field0_vstart, INT32U field1_vstart, CSI_LATCH_DELAY_ENUM delay)
{
	CSI0_CONTROL_SFR	*pCsi0_Reg;
	CSI1_CONTROL_SFR	*pCsi1_Reg;

	if(csiDevNum == 0)
	{
		pCsi0_Reg = (CSI0_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		pCsi0_Reg->CSI_TG_HLSTART = h_start & 0x0FFF;			// Horizontal latch start
		pCsi0_Reg->CSI_TG_VL0START = field0_vstart & 0x0FFF;	// Field 0 vertical latch start
		pCsi0_Reg->CSI_TG_VL1START = field1_vstart & 0x0FFF;	// Field 1 vertical latch start when interlace mode is used
		pCsi0_Reg->CSI_TG_CTRL2 &= ~MASK_CSI_CTRL1_LATCH_DELAY_MASK;
		pCsi0_Reg->CSI_TG_CTRL2 |= delay;
	}
	else
	{
		pCsi1_Reg = (CSI1_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		pCsi1_Reg->CSI_TG_HLSTART = h_start & 0x0FFF;			// Horizontal latch start
		pCsi1_Reg->CSI_TG_VL0START = field0_vstart & 0x0FFF;	// Field 0 vertical latch start
		pCsi1_Reg->CSI_TG_VL1START = field1_vstart & 0x0FFF;	// Field 1 vertical latch start when interlace mode is used
		pCsi1_Reg->CSI_TG_CTRL2 &= ~MASK_CSI_CTRL1_LATCH_DELAY_MASK;
		pCsi1_Reg->CSI_TG_CTRL2 |= delay;
	}
}

void drv_l1_csi_input_latch_timing2_set(INT8U csiDevNum, CSI_LATCH_EDGE_ENUM field, CSI_LATCH_EDGE_ENUM v_reset, CSI_LATCH_EDGE_ENUM v_increase, CSI_LATCH_EDGE_ENUM h_reset)
{
	CSI0_CONTROL_SFR	*pCsi0_Reg;
	CSI1_CONTROL_SFR	*pCsi1_Reg;

	if(csiDevNum == 0)
	{
		pCsi0_Reg = (CSI0_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		// Latch field at falling(0) or rising(1) edge of VSYNC
		if(field == ENUM_CSI_FALLING_EDGE)
		{
			pCsi0_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_FGET;
		}
		else
		{
			pCsi0_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_FGET;
		}

		// Vertical counter increase at falling(0) or rising(1) edge of HSYNC
		if(v_increase == ENUM_CSI_FALLING_EDGE)
		{
			pCsi0_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_VADD;
		}
		else
		{
			pCsi0_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_VADD;
		}

		// Vertical counter reset at falling(0) or rising(1) edge of VSYNC
		if(v_reset == ENUM_CSI_FALLING_EDGE)
		{
			pCsi0_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_VRST;;
		}
		else
		{
			pCsi0_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_VRST;
		}

		// Horizontal counter reset at falling(0) or rising(1) edge of HSYNC
		if(h_reset == ENUM_CSI_FALLING_EDGE)
		{
			pCsi0_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_HRST;
		}
		else
		{
			pCsi0_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_HRST;
		}
	}
	else
	{
		pCsi1_Reg = (CSI1_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		// Latch field at falling(0) or rising(1) edge of VSYNC
		if(field == ENUM_CSI_FALLING_EDGE)
		{
			pCsi1_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_FGET;
		}
		else
		{
			pCsi1_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_FGET;
		}

		// Vertical counter increase at falling(0) or rising(1) edge of HSYNC
		if(v_increase == ENUM_CSI_FALLING_EDGE)
		{
			pCsi1_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_VADD;
		}
		else
		{
			pCsi1_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_VADD;
		}

		// Vertical counter reset at falling(0) or rising(1) edge of VSYNC
		if(v_reset == ENUM_CSI_FALLING_EDGE)
		{
			pCsi1_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_VRST;;
		}
		else
		{
			pCsi1_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_VRST;
		}

		// Horizontal counter reset at falling(0) or rising(1) edge of HSYNC
		if(h_reset == ENUM_CSI_FALLING_EDGE)
		{
			pCsi1_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_HRST;
		}
		else
		{
			pCsi1_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_HRST;
		}
	}
}

void drv_l1_csi_set_buf(INT8U csiDevNum, INT32U buf)
{
	CSI0_CONTROL_SFR	*pCsi0_Reg;
	CSI1_CONTROL_SFR	*pCsi1_Reg;

	if(csiDevNum == 0)
	{
		pCsi0_Reg = (CSI0_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		pCsi0_Reg->CSI_TG_FBSADDR = buf;
	}
	else
	{
		pCsi1_Reg = (CSI1_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		pCsi1_Reg->CSI_TG_FBSADDR = buf;
	}
}

INT32U drv_l1_csi_get_buf(INT8U csiDevNum)
{
	CSI0_CONTROL_SFR	*pCsi0_Reg;
	CSI1_CONTROL_SFR	*pCsi1_Reg;

	if(csiDevNum == 0)
	{
		pCsi0_Reg = (CSI0_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		return(INT32U) pCsi0_Reg->CSI_TG_FBSADDR;
	}
	else
	{
		pCsi1_Reg = (CSI1_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		return(INT32U) pCsi1_Reg->CSI_TG_FBSADDR;
	}
}

void drv_l1_csi_set_buf_B(INT8U csiDevNum, INT32U buf)
{
	CSI0_CONTROL_SFR	*pCsi0_Reg;
	CSI1_CONTROL_SFR	*pCsi1_Reg;

	if(csiDevNum == 0)
	{
		pCsi0_Reg = (CSI0_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		pCsi0_Reg->CSI_TG_FBSADDR_B = buf;
	}
	else
	{
		pCsi1_Reg = (CSI1_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		pCsi1_Reg->CSI_TG_FBSADDR_B = buf;
	}
}

INT32U drv_l1_csi_get_buf_B(INT8U csiDevNum)
{
	CSI0_CONTROL_SFR	*pCsi0_Reg;
	CSI1_CONTROL_SFR	*pCsi1_Reg;

	if(csiDevNum == 0)
	{
		pCsi0_Reg = (CSI0_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		return(INT32U) pCsi0_Reg->CSI_TG_FBSADDR_B;
	}
	else
	{
		pCsi1_Reg = (CSI1_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		return(INT32U) pCsi1_Reg->CSI_TG_FBSADDR_B;
	}
}

void drv_l1_csi_set_long_burst_mode(INT8U csiDevNum, INT8U modeEnable)
{
	CSI0_CONTROL_SFR	*pCsi0_Reg;

	if(csiDevNum == 0)
	{
		pCsi0_Reg = (CSI0_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		if(modeEnable)
		{
			pCsi0_Reg->CSI_SEN_CTRL |= (0x01 << 7);
		}
		else
		{
			pCsi0_Reg->CSI_SEN_CTRL &= ~(0x01 << 7);
		}
	}
}

void drv_l1_csi_set_upscaler_mode(INT8U csiDevNum, CSI_UPSCALER_ENUM upScalerMode)
{
	CSI0_CONTROL_SFR	*pCsi0_Reg;

	if(csiDevNum == 0)
	{
		pCsi0_Reg = (CSI0_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		if(upScalerMode == ENUM_CSI_DISABLE_TO_D1)
		{
			pCsi0_Reg->CSI_TG_CTRL1 &= ~MASK_CSI_CTRL0_VGA_TO_D1;
		}
		else
		if(upScalerMode == ENUM_CSI_640_TO_D1)
		{
			pCsi0_Reg->CSI_TG_CTRL1 &= ~(0x01 << 25);
			pCsi0_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_VGA_TO_D1;
		}
		else
		if(upScalerMode == ENUM_CSI_688_TO_D1)
		{
			pCsi0_Reg->CSI_TG_CTRL1 |= MASK_CSI_CTRL0_VGA_TO_D1 | (0x01 << 25);
		}
	}
}

void drv_l1_csi_register_cbk(INT8U csiDevNum, CSI_CALLBACK_FUN fun)
{
	csi_callback[csiDevNum] = fun;
}

void CSI_IRQHandler(INT8U csiDevNum)
{
	INT32U				flag = 0;
	INT32U				enable = 0;
	INT32U				event = CSI_NONE_EVENT;
	CSI0_CONTROL_SFR	*pCsi0_Reg;
	CSI1_CONTROL_SFR	*pCsi1_Reg;

	if(csiDevNum == 0)
	{
		pCsi0_Reg = (CSI0_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		flag = pCsi0_Reg->CSI_SEN_IRQSTS;
		pCsi0_Reg->CSI_SEN_IRQSTS = flag;
		enable = pCsi0_Reg->CSI_SEN_IRQEN;

		flag &= enable;
		if(flag & MASK_CSI_OUTPUT_FIFO_FLAG)
		{
			/* Sensor FIFO mode occurred */
			event |= CSI_SENSOR_OUTPUT_FIFO_EVENT;
		}

		if(flag & MASK_CSI_FIFO_OVERFLOW_FLAG)
		{
			/* Sensor under run */
			event |= CSI_SENSOR_FIFO_OVERFLOW_EVENT;
		}

		if(flag & MASK_CSI_FRAME_END_FLAG)
		{
			/* Sensor frame end occurred */
			event |= CSI_SENSOR_FRAME_END_EVENT;
		}

		if(event != CSI_NONE_EVENT && csi_callback[csiDevNum] != NULL)
		{
			/* Call callback function come from sensor */
			csi_callback[csiDevNum](event);
		}
	}
	else
	{
		pCsi1_Reg = (CSI1_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		flag = pCsi1_Reg->CSI_SEN_IRQSTS;
		pCsi1_Reg->CSI_SEN_IRQSTS = flag;
		enable = pCsi1_Reg->CSI_SEN_IRQEN;

		flag &= enable;
		if(flag & MASK_CSI_OUTPUT_FIFO_FLAG)
		{
			/* Sensor FIFO mode occurred */
			event |= CSI_SENSOR_OUTPUT_FIFO_EVENT;
		}

		if(flag & MASK_CSI_FIFO_OVERFLOW_FLAG)
		{
			/* Sensor under run */
			event |= CSI_SENSOR_FIFO_OVERFLOW_EVENT;
		}

		if(flag & MASK_CSI_FRAME_END_FLAG)
		{
			/* Sensor frame end occurred */
			event |= CSI_SENSOR_FRAME_END_EVENT;
		}

		if(event != CSI_NONE_EVENT && csi_callback[csiDevNum] != NULL)
		{
			/* Call callback function come from sensor */
			csi_callback[csiDevNum](event);
		}
	}
}

void CSI_0_IRQHandler(void)
{
	CSI_IRQHandler(CSI_DEV_0);
}

void CSI_1_IRQHandler(void)
{
	CSI_IRQHandler(CSI_DEV_1);
}

void drv_l1_csi_set_irq(INT8U csiDevNum, INT32U enable)
{
	if(enable)
	{
		if(csiDevNum == CSI_DEV_0)
		{
			vic_irq_register(VIC_CSI0, CSI_0_IRQHandler);
			vic_irq_enable(VIC_CSI0);
		}
		else
		{
			vic_irq_register(VIC_CSI1, CSI_1_IRQHandler);
			vic_irq_enable(VIC_CSI1);
		}
	}
	else
	{
		if(csiDevNum == CSI_DEV_0)
		{
			vic_irq_disable(VIC_CSI0);
		}
		else
		{
			vic_irq_disable(VIC_CSI1);
		}
	}
}

void drv_l1_csi_set_path_to_pscaler(INT8U csiDevNum, INT32U enable)
{
	CSI0_CONTROL_SFR	*pCsi0_Reg;
	CSI1_CONTROL_SFR	*pCsi1_Reg;

	if(csiDevNum == 0)
	{
		pCsi0_Reg = (CSI0_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);
		if(enable)
		{
			pCsi0_Reg->CSI_TG_CTRL1 |= (0x01 << 24);
		}
		else
		{
			pCsi0_Reg->CSI_TG_CTRL1 &= ~(0x01 << 24);
		}
	}
	else
	{
		pCsi1_Reg = (CSI1_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);
		if(enable)
		{
			pCsi1_Reg->CSI_TG_CTRL1 |= (0x01 << 24);
		}
		else
		{
			pCsi1_Reg->CSI_TG_CTRL1 &= ~(0x01 << 24);
		}
	}
}

/**
* @brief	select sensor mclk out speed for CSI& CDSP Path
* @param	mclk_sel:
*/
void drv_l1_csi_set_clock(MASTER_CLOCK_ENUM clockSelect, MASTER_CLOCK_MIPI_ENUM mipi_en, MASTER_CLOCK_CSI_ENUM csi_en)
{
	CSI0_CONTROL_SFR	*pCsi0_Reg;
	
	INT32U	funpos1 = R_FUNPOS1;

	/*CSI1(R0x410)b[11]: CLK sel No Function,Always use CSI0(R0x244)b[11]*/
	pCsi0_Reg = (CSI0_CONTROL_SFR *) get_CSI_Reg_Base(0);

	if ((funpos1 >> 24 ) && 0xf)	//csi clko(mclk)
	{
		if(clockSelect == MASTER_CLOCK_DISABLE)
		{
			R_SYSTEM_CTRL &= ~MASK_CSICLK_EN;
		}
		else if(clockSelect == MASTER_CLOCK_12MHZ)
		{
			R_SYSTEM_CTRL |= MASK_CSICLK_EN | MASK_SEN_DIV2_SEL;
			
			R_SYSTEM_HDMI_CTRL |= MASK_C27M_EN; //C27M enable
			R_SYSTEM_HDMI_CTRL &= ~0x3F;
			R_SYSTEM_HDMI_CTRL |= 0x17;	//div sys clk(288)/(0x17+1)
			
			pCsi0_Reg->CSI_TG_CTRL2 &= ~MASK_CSI_CTRL1_CLK_SEL;
		}
	
		else if(clockSelect == MASTER_CLOCK_13_5MHZ)
		{
			R_SYSTEM_CTRL |= MASK_CSICLK_EN | MASK_SEN_DIV2_SEL;
			
			R_SYSTEM_HDMI_CTRL |= MASK_C27M_EN; //C27M enable
			R_SYSTEM_HDMI_CTRL &= ~0x3F;
			R_SYSTEM_HDMI_CTRL |= 0x14;	//div sys clk(288)/(0x14+1)
			
			pCsi0_Reg->CSI_TG_CTRL2 &= ~MASK_CSI_CTRL1_CLK_SEL;
		}
		else if(clockSelect == MASTER_CLOCK_27MHZ)
		{
			R_SYSTEM_CTRL |= MASK_CSICLK_EN | MASK_SEN_DIV2_SEL;
			
			R_SYSTEM_HDMI_CTRL |= MASK_C27M_EN; //C27M enable
			R_SYSTEM_HDMI_CTRL &= ~0x3F;
			R_SYSTEM_HDMI_CTRL |= 0xA;	//div sys clk(288)/(0xa+1)
			
			pCsi0_Reg->CSI_TG_CTRL2 &= ~MASK_CSI_CTRL1_CLK_SEL;
		}
		else if(clockSelect == MASTER_CLOCK_48MHZ)
		{
			R_SYSTEM_CKGEN_CTRL |= MASK_XCKG_EN;
			R_SYSTEM_CTRL &= ~MASK_SEN_DIV2_SEL;
			R_SYSTEM_CTRL |= MASK_CSICLK_EN | MASK_SEN_48M_SEL;
			pCsi0_Reg->CSI_TG_CTRL2 |= MASK_CSI_CTRL1_CLK_SEL;
		}
		else //(clockSelect == MASTER_CLOCK_24MHZ)
		{
			R_SYSTEM_CKGEN_CTRL |= MASK_XCKG_EN;
			R_SYSTEM_CTRL |= MASK_CSICLK_EN | MASK_SEN_48M_SEL | MASK_SEN_DIV2_SEL;//MASK_CSICLK_DIV2_EN;
			pCsi0_Reg->CSI_TG_CTRL2 |= MASK_CSI_CTRL1_CLK_SEL;
		}
	}
	else	//cdsp clko(mclk)
	{
		if(clockSelect == MASTER_CLOCK_DISABLE)
		{
			R_SYSTEM_CTRL &= ~MASK_CSICLK_EN;
		}
		else if(clockSelect == MASTER_CLOCK_12MHZ)
		{
			R_SYSTEM_CTRL |= MASK_CSICLK_EN | MASK_CSICLK_DIV2_EN;
			
			R_SYSTEM_HDMI_CTRL |= MASK_C27M_EN; //C27M enable
			R_SYSTEM_HDMI_CTRL &= ~0x3F;
			R_SYSTEM_HDMI_CTRL |= 0x17;	//div sys clk(288)/(0x17+1)
			
			pCsi0_Reg->CSI_TG_CTRL2 &= ~MASK_CSI_CTRL1_CLK_SEL;
		}
	
		else if(clockSelect == MASTER_CLOCK_13_5MHZ)
		{
			R_SYSTEM_CTRL |= MASK_CSICLK_EN | MASK_CSICLK_DIV2_EN;
			
			R_SYSTEM_HDMI_CTRL |= MASK_C27M_EN; //C27M enable
			R_SYSTEM_HDMI_CTRL &= ~0x3F;
			R_SYSTEM_HDMI_CTRL |= 0x14;	//div sys clk(288)/(0x14+1)
			
			pCsi0_Reg->CSI_TG_CTRL2 &= ~MASK_CSI_CTRL1_CLK_SEL;
		}
		else if(clockSelect == MASTER_CLOCK_27MHZ)
		{
			R_SYSTEM_CTRL |= MASK_CSICLK_EN | MASK_CSICLK_DIV2_EN;
			
			R_SYSTEM_HDMI_CTRL |= MASK_C27M_EN; //C27M enable
			R_SYSTEM_HDMI_CTRL &= ~0x3F;
			R_SYSTEM_HDMI_CTRL |= 0xA;	//div sys clk(288)/(0xa+1)
			
			pCsi0_Reg->CSI_TG_CTRL2 &= ~MASK_CSI_CTRL1_CLK_SEL;
		}
		else if(clockSelect == MASTER_CLOCK_48MHZ)
		{
			R_SYSTEM_CKGEN_CTRL |= MASK_XCKG_EN;
			R_SYSTEM_CTRL &= ~MASK_CSICLK_DIV2_EN;
			R_SYSTEM_CTRL &= ~MASK_SEN_DIV2_SEL;	
			R_SYSTEM_CTRL |= MASK_CSICLK_EN | MASK_SEN_48M_SEL;
			pCsi0_Reg->CSI_TG_CTRL2 |= MASK_CSI_CTRL1_CLK_SEL;
		}
		else //(clockSelect == MASTER_CLOCK_24MHZ)
		{
			R_SYSTEM_CKGEN_CTRL |= MASK_XCKG_EN;
			R_SYSTEM_CTRL |= MASK_CSICLK_EN | MASK_SEN_48M_SEL | MASK_CSICLK_DIV2_EN;
			pCsi0_Reg->CSI_TG_CTRL2 |= MASK_CSI_CTRL1_CLK_SEL;
		}
	}

	switch(csi_en)
	{
		case MASTER_CLOCK_CSI_ON:
			pCsi0_Reg->CSI_TG_CTRL2 |= MASK_CSI_CTRL1_CLKOEN;
		break;
		case MASTER_CLOCK_CSI_OFF:
			pCsi0_Reg->CSI_TG_CTRL2 &= ~MASK_CSI_CTRL1_CLKOEN;
		break;
	}
	
	switch(mipi_en)
	{
		case MASTER_CLOCK_MIPI_ON:
			pCsi0_Reg->CSI_TG_CTRL2 |= MASK_CSI_CTRL1_CLK_STOPB;
		break;
		case MASTER_CLOCK_MIPI_OFF:
			pCsi0_Reg->CSI_TG_CTRL2 &= ~MASK_CSI_CTRL1_CLK_STOPB;
		break;
	}

}


void drv_l1_MD_Initial(INT8U csiDevNum,INT32U width, INT32U height, INT32U buf)
{
	INT16U width_blk, height_blk;
	INT32U reg;

	CSI0_CONTROL_SFR	*pCsi0_Reg;
	CSI1_CONTROL_SFR	*pCsi1_Reg;

	width_blk = ((width>>4)-1);
	height_blk = ((height>>4)-1);

	reg = width_blk <<16 | height_blk << 24;
	if(csiDevNum == 0)
	{
		pCsi0_Reg = (CSI0_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		reg |= (MD_THRESHOLD|MD_MODE_SINGLE|MD_YUV|MD_VGA);

		pCsi0_Reg->CSI_MD_FBADDR = buf;
		pCsi0_Reg->CSI_MD_CTRL = reg;
	}
	else
	{
		pCsi1_Reg = (CSI1_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

	}
}


INT32U drv_l1_csi_get_md_buf(INT8U csiDevNum)
{
	CSI0_CONTROL_SFR	*pCsi0_Reg;
	CSI1_CONTROL_SFR	*pCsi1_Reg;

	if(csiDevNum == 0)
	{
		pCsi0_Reg = (CSI0_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		return(INT32U) pCsi0_Reg->CSI_MD_FBADDR;
	}
	else
	{
		pCsi1_Reg = (CSI1_CONTROL_SFR *) get_CSI_Reg_Base(csiDevNum);

		return(INT32U) DUMMY_BUFFER_ADDRS;
	}
}

void drv_l1_csi_set_md_SenstiveThr(INT8U threshold)
{
	CSI0_CONTROL_SFR	*pCsi0_Reg;

	pCsi0_Reg = (CSI0_CONTROL_SFR *) get_CSI_Reg_Base(0);

	pCsi0_Reg->CSI_MD_CTRL &= ~(0x7F << 9);
	pCsi0_Reg->CSI_MD_CTRL |= ((threshold & 0x7F) << 9);
}


INT32U drv_l1_csi_get_md_threshold(void)
{
	INT8U value;
	CSI0_CONTROL_SFR	*pCsi0_Reg;
//	CSI1_CONTROL_SFR	*pCsi1_Reg;

	pCsi0_Reg = (CSI0_CONTROL_SFR *) get_CSI_Reg_Base(0);

	value = ((pCsi0_Reg->CSI_MD_CTRL>>9) & 0x3F);
	return(INT32U) value;
}

void drv_l1_MD_OnOff(INT8U motionOnOff)
{
	CSI0_CONTROL_SFR	*pCsi0_Reg;

	pCsi0_Reg = (CSI0_CONTROL_SFR *) get_CSI_Reg_Base(0);

	if(motionOnOff == 1)
	{
		pCsi0_Reg->CSI_MD_CTRL &= ~MD_EN;
		pCsi0_Reg->CSI_MD_CTRL |= MD_EN;

	}
	else
	{
		pCsi0_Reg->CSI_MD_CTRL &= ~MD_EN;
	}
}
#endif //(defined _DRV_L1_CSI) && (_DRV_L1_CSI == 1)
